/*
 * Copyright 2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.paboo.chart.itf;

import com.google.gson.Gson;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.oned.ITFWriter;
import org.paboo.chart.oned.OneDimensionalEntity;
import org.paboo.util.LoggerFactoryUtils;
import org.paboo.util.ParameterObject;
import org.paboo.util.ResponseUtils;
import org.paboo.util.ZxingImage;
import org.springframework.hateoas.ExposesResourceFor;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.imageio.ImageIO;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * @author Leonard
 */
@RestController
@ExposesResourceFor(OneDimensionalEntity.class)
public class itfController {

    private static final long serialVersionUID = -3954528798381884277L;
    private LoggerFactoryUtils log = LoggerFactoryUtils.getInstance().load(itfController.class);

    @RequestMapping("/itf")
    public ResponseEntity<byte[]> handleControllerExecution(HttpMethod method,
                                                            @RequestParam(value = "data", required = false, defaultValue = "1234567890") String ctx,
                                                            @RequestParam(value = "format", required = false, defaultValue = "png") String format,
                                                            @RequestParam(value = "size", required = false, defaultValue = "128x64") String sizep,
                                                            @RequestBody(required = false) String requestStr) throws IOException {
        OneDimensionalEntity e = new OneDimensionalEntity();
        MediaType mt;

        if (!ParameterObject.hasText(requestStr)) {
            requestStr = "{}";
        }

        //String encoding = StandardCharsets.UTF_8.name();
        if (method == HttpMethod.GET) {
            //encoding = !encoding.isEmpty() ? encoding : StandardCharsets.UTF_8.name();
            //ctx = URLDecoder.decode(ctx, encoding);
            //ctx = new String(ctx.getBytes(encoding), StandardCharsets.ISO_8859_1);
            e.setData(ctx);
            if (!e.getData().matches("\\d*")) {
                return ResponseUtils.sendErrorOverJSON(HttpStatus.NOT_IMPLEMENTED, "Data parameter error!!!");
            }

            e.setFormat(format);
            String[] size = sizep.split("x");
            e.setWidth(Integer.valueOf(size[0]));
            e.setHeight(Integer.valueOf(size[1]));
        } else if (method == HttpMethod.POST) {
            Gson gson = new Gson();
            e = gson.fromJson(requestStr, OneDimensionalEntity.class);
            if (!(ParameterObject.hasText(e.getData()) && e.getData().matches("\\d*"))) {
                e.setData("1234567890");
            }
            if (!ParameterObject.hasText(e.getFormat())) {
                e.setFormat("png");
            }
            if (!ParameterObject.hasInteger(e.getWidth()) || !ParameterObject.hasInteger(e.getWidth())) {
                e.setHeight(64);
                e.setWidth(128);
            }
            log.info(gson.toJson(e));
        } else {
            return ResponseUtils.sendErrorOverJSON(HttpStatus.NOT_IMPLEMENTED, "Request error!!!");
        }

        BitMatrix matrix;
        try {
            matrix = new ITFWriter().encode(e.getData(), BarcodeFormat.ITF, e.getWidth(), e.getHeight(), null);
            log.debug("Matrix size:" + matrix.getWidth() + "x" + matrix.getHeight());
        } catch (Exception ex) {
            String errorMsg = "Create Fail!!!";
            if (log.isDebugEnabled()) {
                log.error(errorMsg, ex);
            } else {
                log.error(errorMsg);
            }
            return ResponseUtils.sendErrorOverJSON(HttpStatus.INTERNAL_SERVER_ERROR, errorMsg);
        }

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        if (!ImageIO.write(ZxingImage.toBufferedImage(matrix, ZxingImage.WHITE, ZxingImage.BLACK), e.getFormat().toLowerCase(), out)) {
            String errmsg = "Could not write an image of format " + e.getFormat().toLowerCase();
            log.error(errmsg);
            return ResponseUtils.sendErrorOverJSON(HttpStatus.INTERNAL_SERVER_ERROR, errmsg);
        }

        if (e.getFormat().equalsIgnoreCase("png")) {
            mt = MediaType.IMAGE_PNG;
        } else if (e.getFormat().equalsIgnoreCase("gif")) {
            mt = MediaType.IMAGE_GIF;
        } else if (e.getFormat().equalsIgnoreCase("jpg") || e.getFormat().equalsIgnoreCase("jpeg")) {
            mt = MediaType.IMAGE_JPEG;
        } else {
            return ResponseUtils.sendErrorOverJSON(HttpStatus.NOT_IMPLEMENTED, "Not implement image format");
        }

        return ResponseUtils.sendOkContent(mt, out.toByteArray());
    }
}
